import xmlrpclib,httplib,urllib2,socket,urlparse,re
from pyleo.lib.BeautifulSoup import BeautifulSoup as BS

def autodiscover(target_url,opener):
    ''' take a target url, and attempt to get the appropriate trackback ping address,
    return the orginal url if nothing is found '''
    # code helped by http://postneo.com/projects/tblib/tblib-0.1.0.html (c) Matt Croydon, GPL
    r=target_url
    try:
        req=urllib2.Request(target_url)
        response=opener.open(req)
        data = response.read()
        tbpattern = r'trackback:ping="(.*?)"'
        reg = re.search(tbpattern, data)
        if reg: r=reg.group(1)
    except:
        pass
    return r
    
def getOpener(proxyServer=None):
    if proxyServer is None:
        proxyHandler=urllib2.ProxyHandler({})
    else:
        #the ping handler requires a bare proxy, here we require the whole thing ...
        proxyServer='http://%s/'%proxyServer
        print proxyServer
        proxyHandler=urllib2.ProxyHandler({'http':proxyServer,'ftp':proxyServer})
    opener=urllib2.build_opener(proxyHandler)
    return opener

def TrackbackPing(target_url,payload,proxyServer=None):
    '''Takes a urlencoded payload and delivers it to a target '''
    response=''
    try:
        opener=getOpener(proxyServer)
        target_url=autodiscover(target_url,opener)
        try:
            req=urllib2.Request(target_url)
            req.add_header('User-Agent','Leonardo - Pinger V0.1')
            req.add_header('Content-Type','application/x-www-form-urlencoded')
            response+="<br/>(trackback POSTed to %s)<br/>[["%target_url
            fd=opener.open(req,payload)
            #urllib2.install_opener(opener)
            #fd=urllib2.urlopen(req,payload)   ### is this a duplicate when the firewall is not an issue?
            for i in fd: response+=i
            response+=']]'
        except Exception,e:
            response= 'Error (%s) in TrackBackPing to target %s'%(str(e),target_url)
    except urllib2.URLError,e:
        if hasattr(e,'reason'):
            response+='Trackback ping error, no access to server [%s]'%e.reason
        elif hasattr(e,'code'):
            response+='Trackback ping error at server [code %s]'%e.code
    except socket.error:
            response+='Trackback ping socket problem'
    except Exception,e:
            response+='Trackback ping error (reason: %s)'%e
    return response


class ProxyTransport(xmlrpclib.Transport):
    ''' Provides a transport layer which exploits proxies '''
    def __init__(self,proxy):
        self.proxy = proxy
        self._use_datetime=0

    def make_connection(self,host):
        self.realhost = host
        return httplib.HTTP(self.proxy)

    def send_request(self, connection, handler, request_body):
        connection.putrequest("POST", 'http://%s%s' % (self.realhost, handler))

    def send_host(self, connection, host):
        connection.putheader('Host', self.realhost)
        
class PageCandidates:
    ''' Take an html page and provide candidate addresses for pinging. We use
    the site_url to ensure we can offer a ping to local pages too '''
    def __init__(self,html,site_url=''):
        self.html=html
        self.site_url=site_url
        self.soup=BS(html)
        self.a=self.soup.findAll('a')
    def geturls(self):
        urls=[]
        uniqueA=[]
        for i in self.a:
            try:
                u=i['href']
                if u not in uniqueA:
                    uniqueA.append(u)
                    if u[0:1]=='/': u=self.site_url+u 
                    urls.append((u,i['href']))
            except KeyError:
                pass # it's probably a local id tag ...
        return urls

class  UpdatePinger:
    ''' Class to manage ping updates via xmlrpclib and the Mark Pilgrim three liner 
    extended for proxy server etc '''
    def __init__(self,blogName,blogURL,proxyServer=None):
	self.blogName=blogName
	self.blogURL=blogURL
        self.pt=None
        if proxyServer is not None:
            self.pt=ProxyTransport(proxyServer)
    def issue(self,target):
        if self.pt is None:
	    s=xmlrpclib.Server(target)
        else:
            s=xmlrpclib.Server(target,transport=self.pt)
        #try:
        r=s.weblogUpdates.ping(self.blogName,self.blogURL)
        #except Exception,e:
        #    r={'flerror':1,'message':str(e)}
         
	return r
if __name__=="__main__":
    import sys
    blog_name="Bryan's Blog"
    blog_url="http://home.badc.rl.ac.uk"
    if len(sys.argv)<>1: 
	target=sys.argv[1]
	if len(sys.argv)==2:
           proxy=None
        else: proxy=sys.argv[2]
    else:
    	target="http://rpc.pingomatic.com"
        proxy="wwwcache3.rl.ac.uk:8080"    
    s=UpdatePinger(blog_name,blog_url,proxyServer=proxy)
    print s.issue(target)
            
